#include "stdafx.h"
#include "BaseSystem.h"

#include "World\World.h"
#include "Time\TimeManager.h"

#include "States\TransitionState.h"
#include "States\GameStateObject.h"

#include "Components\BonhommeComponent.h"
#include "Components\GaulemRenderableComponent.h"

#include "Event.h"

using namespace std;
using namespace ZeEngine;

const u32 BaseSystem::cBreakfastHour = 1;
const u32 BaseSystem::cNightHour = 21;

BaseSystem::BaseSystem(shared_ptr<GameStateObject> pGameStateObject, GameEngine& gameEngine) :  m_pGameStateObject(pGameStateObject),
                                                                                                m_state(BaseState::None),
                                                                                                m_previousState(BaseState::None),
                                                                                                m_GameEngine(gameEngine)
{
}

BaseSystem::~BaseSystem()
{
}

bool BaseSystem::Init(GameEngine& gameEngine)
{
    //Spawn bonhommes
    EntityManager& entityManager = gameEngine.GetEntityManager();
    ResourceManager& resourceManager = gameEngine.GetResourceManager();

    bool fSuccess = true;
    SpriteSheet* pSheet = resourceManager.GetResource<SpriteSheet>("test_spritesheet", "test_sprites");

    m_pTempEntity = entityManager.CreateAndAddEntity("bonhomme_1", "bottom");
    auto animatedComponent = static_cast<AnimatedComponent*>(m_pTempEntity->AddComponent(make_unique<AnimatedComponent>(pSheet)));
    animatedComponent->SetZ(1);
    animatedComponent->SetCurrentAnimation("walk_front");
    m_pTempEntity->AddComponent(make_unique<TransformComponent>(Vector2D<f32>(0, (64 * 4) + (animatedComponent->GetFrameBoundary().h))));
    m_pTempEntity->AddComponent(make_unique<GaulemRenderableComponent>(false));
    m_pTempEntity->AddComponent(make_unique<BonhommeComponent>());

    return true;
}

bool BaseSystem::Update(ZeEngine::GameEngine& gameEngine)
{
    CheckTime();

    //Make the bonhomme walk back and forth if he is idle
    auto pBonhomme = m_pTempEntity->GetComponent<BonhommeComponent>();
    auto pTransform = m_pTempEntity->GetComponent<TransformComponent>();

    auto& world = m_pGameStateObject->GetWorld();

    if (pBonhomme->GetState() == BonhommeComponent::eIdle)
    {
        auto startPosition = pTransform->GetPosition();
        Vector2D<u32> endPosition;
        if (pTransform->GetPosition().GetX() >= 300)
        {
            endPosition = pTransform->GetPosition() + Vector2D<s32>(-200, 0);
        }
        else
        {
            endPosition = pTransform->GetPosition() + Vector2D<s32>(300, 0);
        }

        world.GetPath(startPosition, endPosition, pBonhomme->GetCurrentPath());
        pBonhomme->UpdateNextDestination();
        pBonhomme->ChangeState(BonhommeComponent::eWalking);
    }

    //We got somewhere to go
    if (pBonhomme->GetDestinationRoom() != NULL)
    {
        //Are we in our destination room
        Entity* pCurrentRoom = world.GetRoom(pTransform->GetPosition());

        if (pCurrentRoom == pBonhomme->GetDestinationRoom())
        {
            pBonhomme->UpdateNextDestination();
        }
        else
        {
            auto pDestination = pBonhomme->GetDestinationRoom()->GetComponent<TransformComponent>();

            //Walk left
            if (pDestination->GetPosition().GetX() < pTransform->GetPosition().GetX())
            {
                m_pTempEntity->GetComponent<AnimatedComponent>()->SetCurrentAnimation("walk_backward");
                pTransform->SetPosition(pTransform->GetPosition() + Vector2D<f32>(-2, 0));
            }
            else
            {
                m_pTempEntity->GetComponent<AnimatedComponent>()->SetCurrentAnimation("walk_front");
                pTransform->SetPosition(pTransform->GetPosition() + Vector2D<f32>(2, 0));
            }
        }
    }
    else
    {
        //were there
        pBonhomme->ChangeState(BonhommeComponent::eIdle);
    }
    return true;
}

void BaseSystem::Destroy(ZeEngine::GameEngine& gameEngine)
{

}

void BaseSystem::CheckTime()
{
    BaseState newState = m_state;
    auto timeManager = m_pGameStateObject->GetTimeManager();
    if (timeManager.GetHours() == cBreakfastHour)
    {
        newState = BaseState::Breakfast;
    }
    else if (timeManager.GetHours() == cNightHour)
    {
        newState = BaseState::Night;
    }

    ChangeState(newState);
}

bool BaseSystem::ChangeState(BaseState newState)
{
    bool fSuccess = true;

    if (m_state != newState)
    {
        m_previousState = m_state;

        switch (m_state)
        {
        case BaseState::None:
        case BaseState::Night:
            if (newState == BaseState::Breakfast)
            {
                DoBreakfastState();
            }
            else
            {
                fSuccess = false;
            }
            break;
        case BaseState::Breakfast:
            if (newState == BaseState::Night)
            {
                DoNightState();
            }
            else
            {
                fSuccess = false;
            }
            break;
        }

        if (!fSuccess)
        {
            LOG_ERROR("Invalid state transition");
        }
    }

    return fSuccess;
}

void BaseSystem::DoBreakfastState()
{
    m_state = BaseState::Breakfast;
    m_GameEngine.PushState(make_unique<TransitionState>(5, m_pGameStateObject));
}

void BaseSystem::DoNightState()
{
    m_state = BaseState::Night;
}
